package com.sz.common.base.dao.ext;

import com.sz.common.base.dao.schema.FieldSchema;
import com.sz.common.base.dao.schema.TableSchema;
import com.sz.common.base.utils.EntityUtils;
import org.apache.ibatis.type.JdbcType;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * Package: com.sz.common.base.dao.ext <br>
 * Function: TODO: ADD FUNCTION <br>
 * Author: Charles. <br>
 * Date: 2017-02-23 11:12:00.
 */
public class FieldExpBuilder {
    public static FieldExpBuilder add() {
        return new FieldExpBuilder();
    }

    private Aliases.Row fields = new Aliases.Row();

    /**
     * @param fieldName
     * @param value
     * @return
     */
    public FieldExpBuilder add(String fieldName, Object value) {
        this.add(new FieldExp(fieldName, value));
        return this;
    }

    /**
     * @param fieldName
     * @param value
     * @param jdbcType
     * @return
     */
    public FieldExpBuilder add(String fieldName, Object value, JdbcType jdbcType) {
        this.add(new FieldExp(fieldName, value, jdbcType == null ? null : jdbcType.name()));
        return this;
    }

    /**
     * @param fieldName
     * @param op
     * @param value
     * @param jdbcType
     * @return
     */
    public FieldExpBuilder add(String fieldName, Operator op, Object value, JdbcType jdbcType) {
        return this.add(fieldName,
                (op == null ? null : Operator.getOpString(op)),
                value,
                jdbcType == null ? null : jdbcType.name()
        );
    }

    /**
     * @param fieldName
     * @param op
     * @param value
     * @param jdbcType
     * @return
     */
    public FieldExpBuilder add(String fieldName, String op, Object value, String jdbcType) {
        this.add(new FieldExp(fieldName, value, jdbcType, op));
        return this;
    }

    /**
     * @param fieldName
     * @param op
     * @param value
     * @param jdbcType
     * @param fixed
     * @return
     */
    public FieldExpBuilder add(String fieldName, Operator op, Object value, JdbcType jdbcType, boolean fixed) {
        return this.add(fieldName,
                op == null ? null : Operator.getOpString(op),
                value,
                jdbcType == null ? null : jdbcType.name(),
                fixed);
    }

    /**
     * @param fieldName
     * @param op
     * @param value
     * @param jdbcType
     * @param fixed
     * @return
     */
    public FieldExpBuilder add(String fieldName, String op, Object value, String jdbcType, boolean fixed) {
        this.add(new FieldExp(fieldName, value, jdbcType, op, fixed));
        return this;
    }

    /**
     * @param fieldExp
     * @return
     */
    public FieldExpBuilder add(FieldExp fieldExp) {
        if (fieldExp != null) {
            String fieldName = fieldExp.getName();

            FieldExp existed = null;
            for (FieldExp field : this.fields) {
                if (fieldName.equalsIgnoreCase(field.getName())) {
                    existed = field;
                    break;
                }
            }
            if (existed != null) {
                this.fields.remove(existed);
            }

            this.fields.add(fieldExp);
        }
        return this;
    }


    /**
     * @return
     */
    public Aliases.Row getFields() {
        return this.fields;
    }


    /**
     * @param schema
     * @param fieldAndValues
     * @param excludeEmptyField
     * @return
     */
    public static FieldExpBuilder buildFromMap(final TableSchema schema,
                                               Map<String, Object> fieldAndValues, boolean excludeEmptyField) {
        FieldExpBuilder builder = FieldExpBuilder.add();

        if (fieldAndValues != null && fieldAndValues.size() > 0) {
            for (Map.Entry<String, Object> entry : fieldAndValues.entrySet()) {
                String fieldName = entry.getKey();
                Object value = fieldAndValues.get(fieldName);
                if (value != null) {
                    builder.add(fieldName, value);
                }
                if (value == null && !excludeEmptyField) { //add empty field
                    FieldSchema fieldSchema = schema.getField(fieldName);
                    if (fieldSchema == null || !StringUtils.hasLength(fieldSchema.getDataTypeString())) {
                        String msg = String.format("value of field %s is null, please specify JDBC type of field %s",
                                fieldName, fieldName);
                        throw new IllegalArgumentException(msg);
                    }
                    builder.add(fieldName, null, fieldSchema.getJdbcType());
                }
            }
        }
        return builder;
    }

    /**
     * @param schema
     * @param entity
     * @param excludeEmptyField
     * @return
     */
    public static FieldExpBuilder buildFromEntity(final TableSchema schema,
                                                  Object entity, boolean excludeEmptyField) {
        Map<String, Object> map = EntityUtils.transBean2Map(entity);
        return buildFromMap(schema, map, excludeEmptyField);
    }
}
